def tracer(func):
    calls = 0
    def wrapper(*args, **kwargs):
        nonlocal calls
        calls += 1
        # wrapper.calls += 1
        print('call %s to %s' % (calls, func.__name__))
        return func(*args, **kwargs)
    # wrapper.calls = 0
    return wrapper


@tracer
def spam(a, b, c):
    print(a + b + c)


@tracer
def eggs(x, y):
    print(x ** y)


spam(1, 23, 3)
spam(a=4, b=4, c=34)
eggs(2, 16)
eggs(2, y=4)

class Person:
    def __init__(self, name, pay):
        self.name = name
        self.pay = pay

    @tracer
    def giveRaise(self, percent):
        self.pay *= (1.0 + percent)

    @tracer
    def lastName(self):
        return self.name.split()[-1]

print('methods...')
bob = Person('Bob Smith', 50000)
sue = Person('Sue Jones', 100000)
print(bob.name, sue.name)
sue.giveRaise(.10) 
print(int(sue.pay))
print(bob.lastName(), sue.lastName())         